package com.baitiaojun.security.core.filter;

import com.baitiaojun.common.enums.impl.ServerExpEnums;
import com.baitiaojun.common.exception.ServerException;
import com.baitiaojun.common.utils.object.ObjectUtils;
import com.baitiaojun.common.utils.string.StringUtils;
import com.baitiaojun.security.core.domain.LoginUser;
import com.baitiaojun.security.core.service.AuthenticationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 用户认证过滤器
 */
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private static final String TENANT = "tenant";

    @Autowired
    private AuthenticationService authenticationService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //获取token
        String token = authenticationService.getToken(request);
        if (StringUtils.isEmpty(token)) {
            filterChain.doFilter(request, response); //token为空就放行,不再进行token解析,交给securiry后续认证器处理
            return; //防止security返回过滤器时执行后续代码
        }
        //解析token
        String uuid = authenticationService.parseToken(token);
        if (ObjectUtils.isNull(uuid)) {
            throw new ServerException(ServerExpEnums.EXP_TOKEN_INVALID);
        }
        //获取用户信息
        LoginUser loginUser = authenticationService.getLoginUser(uuid);
        //租户校验不通过则返回无效认证
        if (!checkLoginUser(request, loginUser)) {
            throw new ServerException(ServerExpEnums.EXP_LOGIN_USER);
        }
        //若距离过期时间小于20分钟, 则刷新用户缓存,保证用户持续登陆,以及自动清除缓存未使用用户
        authenticationService.refresh(loginUser);
        //用户信息添加到spring-security管理
        authenticationService.setSecurityContext(loginUser, request);
        //放行
        filterChain.doFilter(request, response);
    }

    /**
     * 租户有效性校验
     * @param request
     * @param loginUser
     * @return
     */
    private boolean checkLoginUser(HttpServletRequest request, LoginUser loginUser) {
        if (loginUser == null) {
            return false;
        }
        String tenant = loginUser.getTenant();
        if (StringUtils.isEmpty(tenant)) {
            return false;
        }
        return tenant.equalsIgnoreCase(request.getHeader(TENANT));
    }
}
